﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace DBMock
{
    /// <summary>
    /// 缓存
    /// </summary>
    public class CacheHelper
    {
        //分类缓存
        private static ConcurrentDictionary<string, ConcurrentDictionary<string, object>> caches =
            new ConcurrentDictionary<string, ConcurrentDictionary<string, object>>();

        //缓存
        private static ConcurrentDictionary<string, object> customCache = new ConcurrentDictionary<string, object>();

        //获取分类缓存
        private static ConcurrentDictionary<string, object> GetCache(string type)
        {
            if (type == null)
            {
                return customCache;
            }
            else { return caches.GetOrAdd(type, new ConcurrentDictionary<string, object>()); }
        }

        /// <summary>
        /// 获取缓存值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="type">缓存类型</param>
        /// <returns></returns>
        public static object Get(string key, string type = null)
        {
            var cache = GetCache(type);

            object value = null;
            cache.TryGetValue(key, out value);

            return value;
        }

        /// <summary>
        /// 获取缓存值
        /// </summary>
        /// <param name="predicate">测试每个元素是否满足函数</param>
        /// <param name="type">缓存类型</param>
        /// <returns></returns>
        public static List<object> Get(Func<KeyValuePair<string, object>, bool> predicate, string type = null)
        {
            var cache = GetCache(type);

            var result = new List<object>();
            if (predicate == null)
                return result;

            result = cache.Where(predicate).Select(p => p.Value).ToList();
            return result;
        }

        /// <summary>
        /// 获取缓存值
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="type">缓存类型</param>
        /// <param name="valueFactory">获取尚未缓存的值，获取后写入缓存</param>
        /// <returns></returns>
        public static T Get<T>(string key, string type = null, Func<string, T> valueFactory = null)
        {
            var cache = GetCache(type);

            object value = null;

            if (cache.TryGetValue(key, out value) && value.GetType() == typeof(T))
            { return (T)value; }

            if (valueFactory != null)
            {
                T tValue = valueFactory(key);
                cache.TryAdd(key, tValue);

                return tValue;
            }

            return default(T);
        }

        /// <summary>
        /// 检查是否包含指定键
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="type">缓存类型</param>
        public static bool Contains(string key, string type = null)
        {
            var cache = GetCache(type);
            return cache.ContainsKey(key);
        }

        /// <summary>
        /// 写入或更新缓存值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="type">缓存类型</param>
        public static void Set(string key, object value, string type = null)
        {
            var cache = GetCache(type);
            cache.AddOrUpdate(key, value, (k, v) => value);
        }

        /// <summary>
        /// 删除缓存值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="type">缓存类型</param>
        /// <returns></returns>
        public static object Remove(string key, string type = null)
        {
            var cache = GetCache(type);

            object value = null;
            cache.TryRemove(key, out value);

            return value;
        }

        /// <summary>
        /// 删除缓存值
        /// </summary>
        /// <param name="predicate">测试每个元素是否满足函数</param>
        /// <param name="type">缓存类型</param>
        /// <returns></returns>
        public static List<object> Remove(Func<KeyValuePair<string, object>, bool> predicate, string type)
        {
            var cache = GetCache(type);

            var result = new List<object>();
            if (predicate == null)
                return result;

            cache.Where(predicate)
                .Select(p => p.Key)
                .ToList()
                .ForEach(k =>
                {
                    object value = null;
                    cache.TryRemove(k, out value);

                    result.Add(value);
                });

            return result;
        }

        /// <summary>
        /// 删除所有缓存
        /// </summary>
        /// <param name="type">缓存类型</param>
        public static void Clear(string type = null)
        {
            var cache = GetCache(type);
            cache.Clear();
        }
    }
}
